package graphics;

import java.awt.Image;
import java.util.ArrayList;
import java.io.Serializable;

/**
    The Animation class manages a series of images (frames) and
    the amount of time to display each frame.
*/
public class Animation implements Serializable{

    private ArrayList frames;
    private int currFrameIndex;
    //private long frameTime;
    private long animTime;
    private long totalDuration;
    private boolean looping;
    private boolean playing;
    //private boolean reverse;


    /**
        Creates a new, empty Animation.
     *  looping by defualt
    */
    public Animation() {
        this(new ArrayList(), 0);
        this.looping=true;
        //this.reverse=false;
    }

    /**
     * Looping is enabled by defualt
     *
     * @param frames
     * @param totalDuration
     */
    private Animation(ArrayList frames, long totalDuration) {
        this.frames = frames;
        this.totalDuration = totalDuration;
        this.looping=true;
        //this.reverse=false;
        start();
    }


    /**
        Creates a duplicate of this animation. The list of frames
        are shared between the two Animations, but each Animation
        can be animated independently.
    */
    public Object clone() {
        return new Animation(frames, totalDuration);
    }


    /**
        Adds an image to the animation with the specified
        duration (time to display the image).
    */
    public synchronized void addFrame(Image image,
        long duration)
    {
        totalDuration += duration;
        frames.add(new AnimFrame(image, totalDuration));
        //frames.add(new AnimFrame(image, duration));
    }


    /**
        Starts this animation over from the beginning.
    */
    public synchronized void start() {
        //System.out.println(this+" size: "+frames.size());
        playing=true;
        animTime = 0;
        //frameTime=0;
        //if(!reverse)
            currFrameIndex = 0;
        //else
        //    currFrameIndex=frames.size()-1;
    }
    
    /*public synchronized void reversePlay(){
        playing=true;
        //reverse=true;
        animTime = 0;
        //frameTime=0;
        currFrameIndex=frames.size()-1;
        System.out.println(this+" started playing reverse frame set to "+currFrameIndex);
    }*/


    /**
        Updates this animation's current image (frame), if
        neccesary.
    */
    public synchronized void update(long elapsedTime) {
        if(playing){
            if (frames.size() > 1) {
                animTime += elapsedTime;
                //frameTime+= elapsedTime;
                
                if (animTime >= totalDuration || currFrameIndex>=frames.size()) {
                    if(!looping)
                        playing=false;
                    else{
                        
                        animTime = animTime % totalDuration;
                        //if(!reverse)
                            currFrameIndex = 0;
                        //else
                        //    currFrameIndex = frames.size()-1;
                    }

                }
                //if(reverse){
                //System.out.println(this+" anim time: "+animTime+"\n"+                            
                //        this+" endTime: "+getFrame(currFrameIndex).endTime);
                //}

                while (animTime > getFrame(currFrameIndex).endTime &&playing) {
                //while (frameTime>=getFrame(currFrameIndex).endTime &&playing){
                    //if(reverse)
                    //    System.out.println(this+"is playing correct");
                    //if(!reverse){
                        currFrameIndex++;
                    //    frameTime=0;
                    //}
                    //else{
                    //    System.out.println(this+" playing reverse frame: "+currFrameIndex);
                    //    currFrameIndex--;
                    //    frameTime=0;
                    //}
                    //if(currFrameIndex>=frames.size())
                    //    break;
                }
            }
        }
    }


    /**
        Gets this Animation's current image. Returns null if this
        animation has no images.
    */
    public synchronized Image getImage() {
        if (frames.size() == 0) {
            return null;
        }
        else {
            return getFrame(currFrameIndex).image;
        }
    }

    public synchronized boolean isLooping() {
        return looping;
    }

    public synchronized void setLooping(boolean looping) {
        this.looping = looping;
    }

    /*public boolean isReverse() {
        return reverse;
    }*

    /*public void setReverse(boolean reverse){
        this.reverse = reverse;
    }*/

    


    private AnimFrame getFrame(int i) {
        return (AnimFrame)frames.get(i);
    }


    private class AnimFrame  implements Serializable{

        Image image;
        long endTime;

        public AnimFrame(Image image, long endTime) {
            this.image = image;
            this.endTime = endTime;
        }
    }
}
